#pragma once
#include "RCGraphicsResource.h"
#include <functional>
#include <sal.h>
#include <exception>
#include <vector>
#include "RCCustomVertex.h"

using namespace RCDX11;
using namespace DirectX;

namespace RCDX11
{
	enum SpriteSortMode
	{
		Deferred = 0,
		Immediate = 1,
		Texture = 2,
		BackToFront = 3,
		FrontToBack = 4,
		Instanced = 5
	};

	class RCSpriteBatch : public RCGraphicsResource
	{
	protected:
		bool bBegan;


		class RCSprite
		{
			public:

				RCSprite(){ }
				virtual ~RCSprite(){ }

				ID3D11ShaderResourceView* texture;
				XMFLOAT2 position;
				XMFLOAT4 color;
				XMFLOAT2 dimensions;
				XMFLOAT2 origin;
				float depth;
				float rotation;
				XMFLOAT4 texMod;
		};

		struct tIdx
		{
			ID3D11ShaderResourceView* texture;
			int Cnt;
			std::shared_ptr<RCSprite> sprite;
		};

		D3D11_SUBRESOURCE_DATA InstData;

		std::vector<std::shared_ptr<RCSprite>> spriteList;

		struct CBParameters
		{
			XMMATRIX MatrixTransform;
			XMFLOAT4 vMeshColor;
			XMFLOAT4 f4TexMods;
		};	

		ID3D11InputLayout* pVertexLayout;
		ID3D11InputLayout* pVertexLayoutInstanced;

		ID3D11VertexShader* pVertexShader;
		ID3D11VertexShader* pVertexShaderInstanced;
		ID3D11PixelShader*  pPixelShader;

		ID3D11Buffer* pVertexBuffer;
		ID3D11Buffer* pInstanceuffer;
		ID3D11Buffer* pIndexBuffer;

		ID3D11Buffer* pParameters;

		XMMATRIX GetViewportTransform();

		PositionTexVertex vertices[4];
		WORD indices[12];
		D3D11_INPUT_ELEMENT_DESC layout[6];
	
		ID3D11BlendState* pBlendState;
		ID3D11DepthStencilState* pDepthStencilState;
		ID3D11SamplerState* pSamplerState;
		ID3D11RasterizerState* pRasterizerState;

		SpriteSortMode SortMode;

		void RenderSprite(std::shared_ptr<RCSprite> sprite);

		std::function<void()> customShader;

		HRESULT CreateBlendState(D3D11_BLEND srcBlend, D3D11_BLEND destBlend, _Out_ ID3D11BlendState** pResult);
		HRESULT CreateDepthStencilState(bool enable, bool writeEnable, _Out_ ID3D11DepthStencilState** pResult);
		HRESULT CreateSamplerState(D3D11_FILTER filter, D3D11_TEXTURE_ADDRESS_MODE addressMode, _Out_ ID3D11SamplerState** pResult);
		HRESULT CreateRasterizerState(D3D11_CULL_MODE cullMode, D3D11_FILL_MODE fillMode, _Out_ ID3D11RasterizerState** pResult);

		XMMATRIX GetSpriteWorld(std::shared_ptr<RCSprite> sprite);
	public:
		DECLDIR RCSpriteBatch(void);
		DECLDIR RCSpriteBatch(IRCGraphicsDevice *graphicsDevice);
		DECLDIR virtual ~RCSpriteBatch(void);

		DECLDIR void Begin(SpriteSortMode sortMode = Deferred, _In_opt_ ID3D11BlendState* blendState = nullptr, _In_opt_ ID3D11SamplerState* samplerState = nullptr, _In_opt_ ID3D11DepthStencilState* depthStencilState = nullptr, _In_opt_ ID3D11RasterizerState* rasterizerState = nullptr, _In_opt_ std::function<void()> setEffect = nullptr);

		DECLDIR void Draw(ID3D11ShaderResourceView* texture, XMFLOAT4 destination, XMFLOAT2 origin, float rotation, XMFLOAT4 color, float depth);
		DECLDIR void Draw(ID3D11ShaderResourceView* texture, XMFLOAT4 source, XMFLOAT4 destination, XMFLOAT2 origin, float rotation, XMFLOAT4 color, float depth);

		DECLDIR void End();

		DECLDIR HRESULT getOpaque(_Out_ ID3D11BlendState** pResult);
		DECLDIR HRESULT getAlphaBlend(_Out_ ID3D11BlendState** pResult);
		DECLDIR HRESULT getAdditive(_Out_ ID3D11BlendState** pResult);
		DECLDIR HRESULT getNonPremultiplied(_Out_ ID3D11BlendState** pResult);
	};


}